package com.qfedu.microuser.user.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qfedu.common.core.entity.User;
import com.qfedu.common.core.utils.JwtUtils;
import com.qfedu.common.core.utils.UserUtils;
import com.qfedu.common.minio.utils.MinioUtil;
import com.qfedu.common.neo4j.node.UserNode;
import com.qfedu.common.neo4j.utils.Neo4jUtils;
import com.qfedu.common.redis.utils.RedisUtil;
import com.qfedu.common.sms.utils.AliSmsUtils;
import com.qfedu.microuser.user.mapper.UserMapper;
import com.qfedu.microuser.user.param.LoginParam;
import com.qfedu.microuser.user.param.RegisterParam;
import com.qfedu.microuser.user.service.UserService;
import com.qfedu.microuser.user.vo.MyVO;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Classname UserServiceImpl
 * @Description TODO
 * @Date 2025-05-21 16:15
 * @Created by 老任与码
 */
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;

    @Resource
    private Neo4jUtils neo4jUtils;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private MinioUtil minioUtil;

    /**
     * 写逻辑，本质就是操作数据，一定要明确有哪些数据，需要什么数据，
     * 需要操作哪些表，需要对这些表进行crud的哪种操作
     *
     * @param registerParam
     */
    @Override
    public void register(RegisterParam registerParam) {
        // 判空
        if (registerParam.getPhone() == null || registerParam.getPhone().equals("")) {
            throw new RuntimeException("必须设置手机号");
        }
        if (!StringUtils.hasLength(registerParam.getUsername())) {
            throw new RuntimeException("用户名不能为空");
        }
        // .....

        // 手机号或者用户名是否唯一
        User user1 = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, registerParam.getUsername()));
        if (user1 != null) {
            throw new RuntimeException("用户名已存在");
        }
        boolean exists = userMapper.exists(Wrappers.lambdaQuery(User.class)
                .eq(User::getPhone, registerParam.getPhone()));
        if (exists) {
            throw new RuntimeException("手机号已存在");
        }

        // 验证码的判断

        // 按断邀请码是否有效
//        Long count = userMapper.selectCount(Wrappers.lambdaQuery(User.class)
//                .eq(User::getInviteCode, registerParam.getInviteCode()));
//        if (count <= 0) {
//            throw new RuntimeException("邀请码错误");
//        }

        User parentUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getInviteCode, registerParam.getInviteCode()));
        if (parentUser == null) {
            throw new RuntimeException("邀请码错误");
        }

        User user = new User();
        // 对象间同名属性的拷贝
        BeanUtils.copyProperties(registerParam, user);
//        user.setUsername(registerParam.getUsername());
//        user.setPassword(registerParam.getPassword());
//        user.setPhone(registerParam.getPhone());

        // 设置父id
        user.setPid(parentUser.getId());

        // 借助hutool工具，生成长度为6位的随机字符串
        String inviteCode = RandomUtil.randomString(6);

        // 判断邀请码是否重复
        Long count2 = userMapper.selectCount(Wrappers.lambdaQuery(User.class)
                .eq(User::getInviteCode, inviteCode));
        // 如果重复，重试3次，如果还重复，进行补偿处理
        if (count2 > 0) {
            // 本例抛出异常，实际也可以重新多次生成
            throw new RuntimeException("邀请码重复");
        }

        user.setInviteCode(inviteCode);
        userMapper.insert(user);

        // 假如neo4j的执行结果，不影响注册的结果，为了提高注册接口的执行效率
        // 可以考虑异步执行图数据库的操作

        // 如果通过线程异步处理逻辑报错了，根据实际的业务，可以启动补偿机制
        threadPoolExecutor.execute(() -> {
            // 将用户信息添加到neo4j
            UserNode pnode = neo4jUtils.getUserNode(parentUser.getId());
            if (pnode == null) {
                pnode = new UserNode();
                pnode.setId(parentUser.getId());
                pnode.setName(parentUser.getUsername());
                // neo4jUtils.addNode(pnode);
            }
            UserNode cnode = new UserNode();
            cnode.setId(user.getId());
            cnode.setName(user.getUsername());

            neo4jUtils.addNode(pnode, cnode);
        });

    }

    @Override
    public String login(LoginParam loginParam) {
        // 判断用户名和密码是否为空


        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, loginParam.getUsername()));
        if (user == null) {
            throw new RuntimeException("用户名错误");
        }
        if (!user.getPassword().equals(loginParam.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        Map<String, Object> map = new HashMap<>();
        map.put("uid", user.getId());
        // 生成jwt表示的token,不用将token存入redis
        String jwt = JwtUtils.createJwt(map);
        return jwt;
    }

    @Override
    public MyVO my() {
        // Integer uid = TokenUtils.getUidFromToken();
        Integer uid = UserUtils.getUid();
        User user = userMapper.selectById(uid);

        MyVO myVO = new MyVO();
        BeanUtils.copyProperties(user, myVO);

        myVO.setSignFlag(0);
        myVO.setPoint(0);
        myVO.setBalance(0);
        return myVO;
    }

    @Override
    public Map<String, Object> invite(Integer uid) {
        // return neo4jUtils.getUserNode(uid);
        return neo4jUtils.findMapById(uid);
    }

    @Override
    public void createCode(String phone) {
        // 生成4位固定长度的纯数字验证码（如：0001, 0123）
        String code = String.format("%04d", RandomUtil.randomInt(10000));

        // 打印日志，确认生成的验证码格式
        System.out.println("生成的验证码: " + code);

        // 将验证码存储到Redis
        redisUtil.setCacheObject("code:" + phone, code, 600, TimeUnit.SECONDS);

        // 发送短信
        AliSmsUtils.sendSms("阿里云短信测试", "SMS_154950909", phone, code);
    }

    @Override
    public String uploadAvatar(MultipartFile file) {
        String filename = file.getOriginalFilename();
        System.out.println("filename: " + filename);

        // 生成唯一文件名（保留原扩展名）
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "_" + filename.substring(filename.lastIndexOf("."));

        // 调用minioUtil.upload获取完整HTTP路径
        String fullUrl = minioUtil.upload(file, filename);
        System.out.println("完整访问URL: " + fullUrl);

        return fullUrl; // 返回完整路径
    }
}
